﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Unity;
using StockholmsStad.Runtime.Serialization.DataContract;
using StockholmsStad.Windows.UI.Infrastructure.Interfaces;
using StockholmsStad.Windows.UI.Modules.Maintenance.Interfaces;
using StockholmsStad.Windows.UI.Facade;
using StockholmsStad.Windows.UI.Modules.Maintenance.Models;
using StockholmsStad.Runtime.Serialization.DataContract.Enums;

namespace StockholmsStad.Windows.UI.Modules.Maintenance.Services
{
    public class CeremonySettingsService : ICeremonySettingsService
    {
        private IApplicationService applicationService;
        private ObservableCollection<ValueIdPair> languages;
        private ObservableCollection<ValueIdPair> ceremonyLanguages;
        private ObservableCollection<ValueIdPair> certificateLanguages;
        private ObservableCollection<ValueIdPair> reportLanguages;
        private ObservableCollection<ValueIdPair> specialNeeds;

        [Dependency]
        public IApplicationService ApplicationService
        {
            set { applicationService = value; }
        }
        
        #region ICeremonySettingsService Members

        public ParvisPropertiesPresentationModel GetParvisProperties()
        {
            var user = applicationService.GetCurrentUser();
            var facade = new MaintenanceFacade(user);
            var properties = facade.GetProperties();
            return CreatePropertiesModel(properties);
        }

        public CeremonyValuesPresentationModel GetCeremonyValues()
        {
            InititalizeValues();

            var model = new CeremonyValuesPresentationModel
                            {
                                NewLanguage = new ValueIdPair(),
                                AllLanguages = languages,
                                CeremonyLanguages = ceremonyLanguages,
                                CertificateLanguages = certificateLanguages,
                                AllReportLanguages = reportLanguages,
                                AllSpecialNeeds = specialNeeds
                            };

            model.AddedLanguage += model_AddedLanguage;
            model.ChangedLanguage += model_ChangedLanguage;
            model.DeletedLanguage += model_DeletedLanguage;
            model.AddedSpecialNeed += model_AddedSpecialNeed;
            model.AddedCeremonyLanguage += model_AddedCeremonyLanguage;
            model.DeletedCeremonyLanguage += model_DeletedCeremonyLanguage;
            model.AddedCertificateLanguage += model_AddedCertificateLanguage;
            model.DeletedCertificateLanguage += model_DeletedCertificateLanguage;
            return model;
        }

        #endregion

        #region Intialize values

        public void InititalizeValues()
        {
            IntitializeLanguages();
            InitializeCeremonyLanguages();
            InitializeCertificateLanguages();
            InitializeReportLanguages();
            InitializeSpecialNeeds();
        }

        private void IntitializeLanguages()
        {
            var user = applicationService.GetCurrentUser();
            var facade = new MaintenanceFacade(user);
            var langs = facade.GetLanguages();
            languages = new ObservableCollection<ValueIdPair>(langs);
       }

        private void InitializeCeremonyLanguages()
        {
            var user = applicationService.GetCurrentUser();
            var facade = new CeremonyFacade(user);
            var langs = facade.GetCeremonyLanguages();
            ceremonyLanguages = new ObservableCollection<ValueIdPair>(langs);
        }

        private void InitializeCertificateLanguages()
        {
            var user = applicationService.GetCurrentUser();
            var facade = new CeremonyFacade(user);
            var langs = facade.GetCertificateLanguages();
            certificateLanguages = new ObservableCollection<ValueIdPair>(langs);
        }

        private void InitializeReportLanguages()
        {
            var user = applicationService.GetCurrentUser();
            var facade = new MaintenanceFacade(user);
            var langs = facade.GetLanguagesForCertificateType(MarriageCertificateType.Wedding);
            reportLanguages = new ObservableCollection<ValueIdPair>(langs);
        }

        private void InitializeSpecialNeeds()
        {
            var user = applicationService.GetCurrentUser();
            var facade = new CeremonyFacade(user);
            var langs = facade.GetSpecialNeeds();
            specialNeeds = new ObservableCollection<ValueIdPair>(langs);
        }

        #endregion

        #region Events

        private void PropertiesSaved(object sender, DataEventArgs<ParvisPropertiesPresentationModel> e)
        {
            if (e != null && e.Value != null)
            {
                ParvisPropertiesPresentationModel model = e.Value;
                ParVisProperties properties = CreateParvisProperties(model);
                var user = applicationService.GetCurrentUser();
                var facade = new MaintenanceFacade(user);
                facade.UpdateProperties(properties);
            }
        }

        private void model_AddedSpecialNeed(object sender, DataEventArgs<CeremonyValuesPresentationModel> e)
        {
            if (e != null && e.Value != null)
            {
                var model = e.Value;
                var user = applicationService.GetCurrentUser();
                var facade = new MaintenanceFacade(user);
                int id = facade.AddSpecialNeed(model.NewSpecialNeed.Name);
                var added = new ValueIdPair() { Id = id, Name = model.NewSpecialNeed.Name };
                specialNeeds.Add(added);
                model.NewSpecialNeed = new ValueIdPair(); // reset the field
            }
        }

        private void model_AddedLanguage(object sender, DataEventArgs<CeremonyValuesPresentationModel> e)
        {
            if (e != null && e.Value != null)
            {
                var model = e.Value;
                var user = applicationService.GetCurrentUser();
                var facade = new MaintenanceFacade(user);
                int id = facade.AddLanguage(model.NewLanguage.Name);
                model.NewLanguage.Id = id;

                languages.Add(model.NewLanguage);
                model.NewLanguage = new ValueIdPair(); // reset the field
            }
        }

        private void model_ChangedLanguage(object sender, DataEventArgs<CeremonyValuesPresentationModel> e)
        {
            if (e != null && e.Value != null)
            {
                var model = e.Value;
                var user = applicationService.GetCurrentUser();
                var facade = new MaintenanceFacade(user);
                facade.UpdateLanguage(model.NewLanguage);

                //Refresh languages
                refreshLanguages(model.NewLanguage);
            }
        }

        private void refreshLanguages(ValueIdPair language)
        {
            refreshLanguage(language, languages);
            refreshLanguage(language, certificateLanguages);
            refreshLanguage(language, ceremonyLanguages);
        }

        private static void refreshLanguage(ValueIdPair language, ObservableCollection<ValueIdPair> languages)
        {
            int addIndex = -1;
            for (int i = 0; i < languages.Count; i++)
            {
                if (languages[i].Id == language.Id)
                {
                    addIndex = i;
                    break;
                }
            }
            if (addIndex > 0)
            {
                languages.RemoveAt(addIndex);
                languages.Insert(addIndex, language);
            }
        }

        private void model_DeletedLanguage(object sender, DataEventArgs<CeremonyValuesPresentationModel> e)
        {
            if (e != null && e.Value != null)
            {
                var model = e.Value;
                var user = applicationService.GetCurrentUser();
                var facade = new MaintenanceFacade(user);
                facade.DeleteLanguage(model.NewLanguage);

                languages.Remove(model.NewLanguage);
                model.NewLanguage = new ValueIdPair(); // reset the field
            }
        }

        private void model_DeletedCeremonyLanguage(object sender, DataEventArgs<CeremonyValuesPresentationModel> e)
        {
            if (e != null && e.Value != null)
            {
                var model = e.Value;
                var user = applicationService.GetCurrentUser();
                var facade = new MaintenanceFacade(user);
                facade.DeleteCeremonyLanguage(model.NewCeremonyLanguage);
                ceremonyLanguages.Remove(model.NewCeremonyLanguage);
                model.NewCeremonyLanguage = new ValueIdPair(); // reset the field
            }
        }

        void model_AddedCertificateLanguage(object sender, DataEventArgs<CeremonyValuesPresentationModel> e)
        {
            if (e != null && e.Value != null)
            {
                var model = e.Value;
                var user = applicationService.GetCurrentUser();
                var facade = new MaintenanceFacade(user);
                int id = facade.AddCertificateLanguage(model.NewCertificateLanguage.Name);
                //Så att vi inte förstör referensen till language collectionen
                var added = new ValueIdPair() { Id = id, Name = model.NewCertificateLanguage.Name };
                certificateLanguages.Add(added);
                model.NewCertificateLanguage = new ValueIdPair(); // reset the field
            }
        }

        void model_DeletedCertificateLanguage(object sender, DataEventArgs<CeremonyValuesPresentationModel> e)
        {
            if (e != null && e.Value != null)
            {
                var model = e.Value;
                var user = applicationService.GetCurrentUser();
                var facade = new MaintenanceFacade(user);
                facade.DeleteCertificateLanguage(model.NewCertificateLanguage);
                certificateLanguages.Remove(model.NewCertificateLanguage);
                model.NewCertificateLanguage = new ValueIdPair(); // reset the field
            }
        }

        void model_AddedCeremonyLanguage(object sender, DataEventArgs<CeremonyValuesPresentationModel> e)
        {
            if (e != null && e.Value != null)
            {
                var model = e.Value;
                var user = applicationService.GetCurrentUser();
                var facade = new MaintenanceFacade(user);
                int id = facade.AddCeremonyLanguage(model.NewCeremonyLanguage.Name);
                //Så att vi inte förstör referensen till language collectionen
                var added = new ValueIdPair() { Id = id, Name = model.NewCeremonyLanguage.Name };
                ceremonyLanguages.Add(added);
                model.NewCeremonyLanguage = new ValueIdPair(); // reset the field
            }
        }

        #endregion

        #region Converters

        private static ParVisProperties CreateParvisProperties(ParvisPropertiesPresentationModel model)
        {
            var properties = new ParVisProperties
                                 {
                                     ApplicationChangeDateIndividualBookingDays =
                                         model.ApplicationChangeDateIndividualBookingDays,
                                     ApplicationChangeDateOrdinaryBookingDays =
                                         model.ApplicationChangeDateOrdinaryBookingDays,
                                     ImpedimentDocValidMonths = model.ImpedimentDocValidMonths,
                                     IndividualImpedimentDocReminderAtDays = model.IndividualImpedimentDocReminderAtDays,
                                     IndividualImpedimentDocRemoveBookingAtDays =
                                         model.IndividualImpedimentDocRemoveBookingAtDays,
                                     IndividualPreliminaryBookingEarliestDays =
                                         model.IndividualPreliminaryBookingEarliestDays,
                                     ReminderOfDocumentsIndividualBookingDays = model.ReminderOfDocumentsIndividualBookingDays,
                                     ReminderOfServiceOrdinaryBookingDays = model.ReminderOfServiceOrdinaryBookingDays,
                                     OrdinaryImpedimentDocReminderAtDays = model.OrdinaryImpedimentDocReminderAtDays,
                                     OrdinaryImpedimentDocRemoveBookingAtDays =
                                         model.OrdinaryImpedimentDocRemoveBookingAtDays,
                                     OrdinaryPreliminaryBookingEarliestDays =
                                         model.OrdinaryPreliminaryBookingEarliestDays
                                 };

            return properties;            
        }

        private ParvisPropertiesPresentationModel CreatePropertiesModel(ParVisProperties properties)
        {
            var model = new ParvisPropertiesPresentationModel
                            {
                                ApplicationChangeDateIndividualBookingDays =
                                    properties.ApplicationChangeDateIndividualBookingDays,
                                ApplicationChangeDateOrdinaryBookingDays =
                                    properties.ApplicationChangeDateOrdinaryBookingDays,
                                ImpedimentDocValidMonths = properties.ImpedimentDocValidMonths,
                                IndividualImpedimentDocReminderAtDays = properties.IndividualImpedimentDocReminderAtDays,
                                IndividualImpedimentDocRemoveBookingAtDays =
                                    properties.IndividualImpedimentDocRemoveBookingAtDays,
                                IndividualPreliminaryBookingEarliestDays =
                                    properties.IndividualPreliminaryBookingEarliestDays,
                                ReminderOfDocumentsIndividualBookingDays = properties.ReminderOfDocumentsIndividualBookingDays,
                                ReminderOfServiceOrdinaryBookingDays = properties.ReminderOfServiceOrdinaryBookingDays,
                                OrdinaryImpedimentDocReminderAtDays = properties.OrdinaryImpedimentDocReminderAtDays,
                                OrdinaryImpedimentDocRemoveBookingAtDays =
                                    properties.OrdinaryImpedimentDocRemoveBookingAtDays,
                                OrdinaryPreliminaryBookingEarliestDays =
                                    properties.OrdinaryPreliminaryBookingEarliestDays
                            };
            model.Saved += PropertiesSaved;

            return model;
        }

        #endregion
    }
}